﻿#region Copyright

// All Material Copyright © 2010 Dynamic Concepts Development Corp., All Rights Reserved.
//      Portions Copyright © 1984-2009 Dynamic Concepts Development Corp., All Rights Reserved.
// For further information please contact: SoftwareSupport@dynconcepts.com
// Dynamic Concepts Development Corp.  311 W 57th St. Suite #422, New York, NY 10019

#endregion

#region Using References

using System;
using System.Threading;
using DynConDevCorp.OpenArch.SupportLibrary.ApplicationInfrastructure;
using DynConDevCorp.OpenArch.SupportLibrary.ParallelExecution.Events;

#endregion

namespace DynConDevCorp.OpenArch.SupportLibrary.ParallelExecution.Scheduling
{
    public static class ScheduledExecutionEnvironment
    {
        #region Public Methods

        public static void Enqueue(ScheduledExecutionItem item)
        {
            sr_ExecutionQueue.Enqueue(item);
            DateTime nextWakeUp = DateTime.UtcNow + sr_ExecutionQueue.TimeTillNextItem;
            s_TimingThreadSleepUntil = nextWakeUp;
        }

        public static void Initialize()
        {
            s_ExecutionThread = new Thread(CreateExecutionThreadHandler) {Name = "Scheduled Execution Environment Thread"};
            s_ExecutionThread.Start();
            s_TimingThread = new Thread(CreateTimingThreadHandler) {Name = "Scheduled Execution Timing Thread"};
            s_TimingThread.IsBackground = true;
            s_TimingThread.Start();

            WaitForThreadedInstanceStarted();
        }

        public static void ShutdownTimingThread()
        {
            s_ExitTimingThread = true;
        }

        #endregion

        #region Internal Methods

        internal static void ThreadedInstanceStarted()
        {
            sr_Sync.Release();
        }

        #endregion

        #region Private Methods

        private static void CreateExecutionThreadHandler()
        {
            ParallelHostThread.CreateNew(new ScheduledExecutionEnvironmentThreadedTask(), ScheduledExecutionEnvironmentThreadStarted);
        }

        private static void CreateTimingThreadHandler()
        {
            while (!s_ExitTimingThread)
            {
                if (TimingThreadWait(TimeSpan.FromMilliseconds(50)))
                {
                }
                else
                {
                }
                if (s_TimingThreadSleepUntil != DateTime.MinValue)
                {
                    if (DateTime.UtcNow > s_TimingThreadSleepUntil)
                    {
                        ScheduledExecutionEnvironmentEvent.Execute(null, new ScheduledExecutionEnvironmentEventArgs(DequeueCurrentItem, sr_ExecutionQueue));
                    }
                }
            }
        }

        private static void DequeueCurrentItem(object context)
        {
            ScheduledExecutionItem item = sr_ExecutionQueue.Dequeue();
            if (item != null)
            {
                item.Execute(null, new EventArgs());
                if (item.RepeatRate != TimeSpan.MaxValue)
                {
                    item.NextExecutionTime = item.NextExecutionTime + item.RepeatRate;
                    sr_ExecutionQueue.Enqueue(item);
                }
            }
        }

        private static void EventCompleted(object sender, EventArgs args)
        {
            QueuedLogger.GlobalInstance.Log(QueuedLogger.MessageSeverity.Debug, "EventCompleted()");
        }

        private static void ScheduledExecutionEnvironmentThreadStarted(object sender, EventArgs args)
        {
            QueuedLogger.GlobalInstance.Log(QueuedLogger.MessageSeverity.Debug, "ScheduledExecutionEnvironment.ScheduledExecutionEnvironmentThreadStarted()");
            ThreadedInstanceStarted();
        }

        private static bool TimingThreadWait(TimeSpan timeout)
        {
            return sr_TimingSync.WaitOne(timeout);
        }

        private static void TriggerTimingThread()
        {
            sr_TimingSync.Release();
        }

        private static void WaitForThreadedInstanceStarted()
        {
            sr_Sync.WaitOne();
        }

        #endregion

        #region Static Fields and Constants

        internal static readonly ParallelEvent<ScheduledExecutionEnvironmentEventArgs> ScheduledExecutionEnvironmentEvent = new ParallelEvent<ScheduledExecutionEnvironmentEventArgs>();
        private static Thread s_ExecutionThread;
        private static bool s_ExitTimingThread;
        private static Thread s_TimingThread;
        private static DateTime s_TimingThreadSleepUntil = DateTime.MinValue;
        private static readonly ScheduledExecutionQueue sr_ExecutionQueue = new ScheduledExecutionQueue();
        private static readonly Semaphore sr_Sync = new Semaphore(0, 1);
        private static readonly Semaphore sr_TimingSync = new Semaphore(0, 1);

        #endregion
    }

    public delegate void ScheduledExecutionEnvironmentDelegate(object context);
}